#include <stdio.h>
#include <stdlib.h>
/* You will to add includes here */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>

// Included to get the support library
#include "calcLib.h"

#define MAXRECVSIZE 1500            //接受来自服务端信息的数组长度

bool if_send_timeout = false;

int main(int argc, char *argv[]) {
    const char *delim = ":";
    const char *server_ip = strtok(argv[1], delim);
    int server_port = atoi(strtok(NULL, delim));

    if (argc > 2) {
        if_send_timeout = true;
    }

    /* Do magic */
    int sockfd;                             //客户端的套接字
    char recv_buf[MAXRECVSIZE];             //客户端存储服务端信息的数组
    struct hostent *he;                     //服务端的主机信息
    struct sockaddr_in server;              //服务端的地址信息
    int recv_num;                           //每次接受的字节数

    //判断参数
    if (argc < 2) {
        printf("[Client] Error: argument number wrong. dir: %s argument num: (%d)\n", argv[0], argc);
        exit(1);
    }

    printf("[Client] Info: getting server info\n");
    //获取服务端主机信息
    if ((he = gethostbyname(server_ip)) == NULL) {
        printf("[Client] Error: client cannot get server host info\n");
        exit(1);
    }

    printf("[Client] Info: creating a socket\n");
    //创建客户端套接字
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("[Client] Error: client cannot create a socket\n");
        exit(1);
    }

    bzero(&server, sizeof(server));    //初始化服务地址信息
    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip);

    printf("[Client] Info: connecting to server\n");
    if (connect(sockfd, (struct sockaddr *) &server, sizeof(server)) == -1) {    //请求与服务端建立连接
        printf("[Client] Error: client cannot connect to server\n");
        exit(1);
    }

    printf("[Client] Info: establish a connection to server %s:%d\n", inet_ntoa(server.sin_addr),
           htons(server.sin_port));

    if ((recv_num = recv(sockfd, recv_buf, MAXRECVSIZE, 0)) == -1) {        //接收来自服务端的协议协商报文
        printf("[Client] Error:client cannot receive data from server\n");
        exit(1);
    }

    recv_buf[recv_num] = '\0';    //为了在后续调用strcmp函数时与字符串常量成功进行比较，即模拟字符串常量以"\0"作为结尾

    printf("[Client] Info: server support communicating protocols as follows:\n\"%s\"\n", recv_buf);
    char *serverproto;    //保存服务端支持的协议名
    bool ifserversupport = false;    //标记是否已经从服务端支持的协议堆中找到自己也支持的协议

    serverproto = strtok(recv_buf, "\n");    //分割字符串，将一个个协议分割出来

    //如果找到，则返回OK.如果没找到，则返回Not OK，并终止通讯
    while (serverproto != NULL) {
        if (strcmp(serverproto, "TEXT TCP 1.0") == 0) {
            const char *response = "OK";
            send(sockfd, response, sizeof(response), 0);
            ifserversupport = true;
            printf("[Client] Info: OK, achieve agreement on communicating protocol with server\n");
            break;
        }
        serverproto = strtok(NULL, "\n");
    }
    if (!ifserversupport) {
        printf("[Client] Info: Client do not support server-side communicating protocol\n");
        send(sockfd, "Not OK", 7, 0);
        close(sockfd);
        exit(1);
    }

    bzero(recv_buf, sizeof(recv_buf));
    if ((recv_num = recv(sockfd, recv_buf, MAXRECVSIZE, 0)) == -1) {        //接收来自服务端的计算题目
        printf("[Client] Error: error in receiving data from server\n");
        close(sockfd);
        exit(1);
    }

    double fresult;
    int result;
    char answer[100];    //保存自己计算出的答案
    char *op;    //保存计算类型（加减乘除）
    op = strtok(recv_buf, " ");
    if (op[0] == 'f') {
        double value1 = atof(strtok(NULL, " "));
        double value2 = atof(strtok(NULL, " "));
        if (op[1] == 'a') {
            fresult = value1 + value2;
        } else if (op[1] == 's') {
            fresult = value1 - value2;
        } else if (op[1] == 'm') {
            fresult = value1 * value2;
        } else {
            fresult = value1 / value2;
        }
        sprintf(answer, "%8.8g", fresult);
        printf("[Client] Info: receive command \"%s %f %f\" from server\n[Client] Info: send answer %s back to server\n",
               op, value1, value2, answer);
    } else {
        int value1 = atoi(strtok(NULL, " "));
        int value2 = atoi(strtok(NULL, " "));
        if (op[0] == 'a') {
            result = value1 + value2;
        } else if (op[0] == 's') {
            result = value1 - value2;
        } else if (op[0] == 'm') {
            result = value1 * value2;
        } else {
            result = value1 / value2;
        }
        sprintf(answer, "%d", result);
        printf("[Client] Info: receive command \"%s %d %d\" from server\n[Client] Info: send answer %s back to server\n",
               op, value1, value2, answer);
    }
    if (if_send_timeout) {
        sleep(10);
    }
    send(sockfd, answer, sizeof(answer), 0);    //返回答案给服务端

    bzero(recv_buf, sizeof(recv_buf));          //初始化重新利用接受消息数组
    if ((recv_num = recv(sockfd, recv_buf, MAXRECVSIZE, 0)) == -1) {        //接收服务端计算出的正确答案
        printf("[Client] Error: error in receiving data from server\n");
        close(sockfd);
        exit(1);
    }
    if (strcmp(recv_buf, "ERROR\0") != 0) {
        printf("[Client] Info: server: the right answer should be %s\n", recv_buf);

        bzero(recv_buf, sizeof(recv_buf));
        if ((recv_num = recv(sockfd, recv_buf, MAXRECVSIZE, 0)) == -1) {        //接受服务端返回的结果
            printf("[Client] Error: error in receiving data from server\n");
            close(sockfd);
            exit(1);
        }
        printf("[Client] Info: server -> %s\n", recv_buf);
    } else {
        printf("[Client] Error: server -> %s\n", recv_buf);
    }

    close(sockfd);

    return 0;

}
